﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Security.Cryptography.X509Certificates;
using System.IO;
using System.Xml;
using Microsoft.SystemCenter.Orchestrator.Integration;

namespace Inframon.IntegrationPack.WindowsAzure
{
    [Activity("Create SQL Database")]
    public class CreateSqlDatabase : IActivity
    {
        [ActivityConfiguration(Usage = ConfigurationUsage.DesignAndExecute), ActivityOutput]
        public AzureSettings Settings { get; set; }

        public void Design(IActivityDesigner designer)
        {
            // Define activity inputs
            designer.AddInput("Server");
            designer.AddInput("DB Name");
            designer.AddInput("Edition").WithListBrowser("Web","Business").NotRequired();
            designer.AddInput("Max Size").NotRequired();
            designer.AddInput("Collation").NotRequired().WithDefaultValue("SQL_Latin1_General_CP1_CI_AS");

            // Define activity outputs
            designer.AddOutput("MS Request ID");
            designer.AddOutput("Status Code");
            designer.AddOutput("Name");

            // Define error outputs
            designer.AddOutput("HTTP Code");
            designer.AddOutput("Exception");
            designer.AddOutput("Stack Trace");
        }

        public void Execute(IActivityRequest request, IActivityResponse response)
        {
            try
            {
                string dbEdition = string.Empty;
                string dbSize = string.Empty;

                // Check if size and edition are null
                if (string.IsNullOrEmpty(request.Inputs["Max Size"].ToString()) && string.IsNullOrEmpty(request.Inputs["Edition"].ToString()))
                {
                    // MAXSIZE and EDITION not specified
                    dbEdition = "Web";
                    dbSize = "1";
                }

                // Check size and set edition if not set
                else if (request.Inputs["Max Size"].ToString() == "1" || request.Inputs["Max Size"].ToString() == "5" && string.IsNullOrEmpty(request.Inputs["Edition"].ToString()))
                {
                    // Size set to 1 or 5 and edition not set
                    dbEdition = "Web";
                    dbSize = request.Inputs["Max Size"].ToString();
                }

                // Check size and set edition if not set
                else if (request.Inputs["Max Size"].AsInt32() >= 10 && string.IsNullOrEmpty(request.Inputs["Edition"].ToString()))
                {
                    // Size set to 1 or 5 and edition not set
                    dbEdition = "Business";
                    dbSize = request.Inputs["Max Size"].ToString();
                }
                else
                {
                    // Use sent inputs
                    dbEdition = request.Inputs["Edition"].ToString();
                    dbSize = request.Inputs["Max Size"].ToString();
                }

                string url = string.Format("https://management.core.windows.net:8443/{0}/services/sqlservers/servers/{1}/databases", Settings.SubscriptionId, request.Inputs["Server"].ToString());
                HttpWebRequest webRequest = HttpWebRequest.Create(url) as HttpWebRequest;

                webRequest.ClientCertificates.Add(new X509Certificate2(Settings.PfxFilePath, Settings.PfxPassword));
                webRequest.Headers["x-ms-version"] = "2012-03-01";
                webRequest.Method = "POST";

                // Prepare XML payload
                string xmlBody;
                xmlBody = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" +
                                 "<ServiceResource xmlns=\"http://schemas.microsoft.com/windowsazure\">\n" +
                                 "  <Name>" + request.Inputs["DB Name"].ToString() + "</Name>\n" +
                                 "  <Edition>" + dbEdition + "</Edition>\n" +
                                 "  <MaxSizeGB>" + dbSize + "</MaxSizeGB>\n" +
                                 "  <CollationName>" + request.Inputs["Collation"].ToString() + "</CollationName>\n" +
                                 "</ServiceResource>";

                byte[] bytes = Encoding.UTF8.GetBytes(xmlBody);
                webRequest.ContentLength = bytes.Length;
                webRequest.ContentType = "application/xml;charset=utf-8";
                using (Stream requestStream = webRequest.GetRequestStream())
                {
                    requestStream.Write(bytes, 0, bytes.Length);
                }

                using (WebResponse webResponse = webRequest.GetResponse())
                {

                    //=== x-ms-request-id is useful for troubleshooting request failures with Microsoft ===//
                    response.Publish("MS Request ID", webResponse.Headers["x-ms-request-id"]);
                    response.Publish("Status Code", (int)((HttpWebResponse)webResponse).StatusCode);

                    using (Stream stream = webResponse.GetResponseStream())
                    {
                        using (XmlTextReader xmlReader = new XmlTextReader(stream))
                        {
                            while (xmlReader.Read())
                            {
                                switch (xmlReader.NodeType)
                                {
                                    case XmlNodeType.Element:
                                        if (xmlReader.Name == "Name")
                                        {
                                            if (xmlReader.Read() && (xmlReader.NodeType == XmlNodeType.Text))
                                            {
                                                // Publish server name of new server
                                                response.Publish("Name", xmlReader.Value.ToString());
                                            }
                                        }
                                        break;
                                }
                            }
                        }
                    }
                }
            }
            catch (WebException webEx)
            {
                // Write exception to output
                response.Publish("Exception", webEx.ToString());

                try
                {
                    HttpWebResponse errorResponse = (HttpWebResponse)webEx.Response;

                    // Write HTTP error code
                    response.Publish("HTTP Code", (int)errorResponse.StatusCode);

                    using (Stream errorResponseStream = errorResponse.GetResponseStream())
                    {
                        using (StreamReader sr = new StreamReader(errorResponseStream))
                        {
                            ////Console.WriteLine(sr.ReadToEnd());
                        }
                    }
                }
                catch (Exception innerEx)
                {
                    response.Publish("Exception", innerEx.ToString());
                    response.Publish("Stack Trace", innerEx.StackTrace.ToString());
                }
            }
            catch (Exception ex)
            {
                // Report error event
                response.ReportErrorEvent(ex.Message, ex.StackTrace);
            }
        }
    }
}